﻿using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using iWare.Wms.Core;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq.Dynamic.Core;

namespace iWare.Wms.Application
{
    /// <summary>
    /// 任务管理
    /// </summary>
    [ApiDescriptionSettings("仓库作业", Name = "WmsTask", Order = 100)]
    [Route("api/[Controller]")]
    public class WmsTaskService : IWmsTaskService, IDynamicApiController, ITransient
    {
        private readonly IRepository<WmsContainer, MasterDbContextLocator> _wmsContainerRep;
        private readonly IRepository<WmsMaterial, MasterDbContextLocator> _wmsMaterialRep;
        private readonly IRepository<WmsMaterialContainer, MasterDbContextLocator> _wmsMaterialContainerRep;
        private readonly IRepository<WmsArea, MasterDbContextLocator> _wmsAreaRep;
        private readonly IRepository<WmsPlace, MasterDbContextLocator> _wmsPlaceRep;
        private readonly IRepository<WmsTask, MasterDbContextLocator> _wmsTaskRep;
        private readonly IRepository<WmsMaterialStock, MasterDbContextLocator> _wmsMaterialStockRep;
        private readonly IRepository<WmsContainerPlace, MasterDbContextLocator> _wmsContainerPlaceRep;


        public WmsTaskService(
            IRepository<WmsContainer, MasterDbContextLocator> wmsContainerRep,
            IRepository<WmsMaterial, MasterDbContextLocator> wmsMaterialRep,
            IRepository<WmsMaterialContainer, MasterDbContextLocator> wmsMaterialContainerRep,
            IRepository<WmsArea, MasterDbContextLocator> wmsAreaRep,
            IRepository<WmsPlace, MasterDbContextLocator> wmsPlaceRep,
            IRepository<WmsTask, MasterDbContextLocator> wmsTaskRep,
            IRepository<WmsMaterialStock, MasterDbContextLocator> wmsMaterialStockRep,
            IRepository<WmsContainerPlace, MasterDbContextLocator> wmsContainerPlaceRep
        )
        {
            _wmsContainerRep = wmsContainerRep;
            _wmsMaterialRep = wmsMaterialRep;
            _wmsMaterialContainerRep = wmsMaterialContainerRep;
            _wmsAreaRep = wmsAreaRep;
            _wmsPlaceRep = wmsPlaceRep;
            _wmsTaskRep = wmsTaskRep;
            _wmsMaterialStockRep = wmsMaterialStockRep;
            _wmsContainerPlaceRep = wmsContainerPlaceRep;
        }

        /// <summary>
        /// 分页查询任务管理
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("page")]
        public async Task<PageResult<WmsTaskOutput>> Page([FromQuery] WmsTaskSearch input)
        {
            var wmsTasks = await _wmsTaskRep.DetachedEntities
                                     .Where(!string.IsNullOrEmpty(input.Taskno), u => EF.Functions.Like(u.TaskNo, $"%{input.Taskno.Trim()}%"))
                                     .Where(input.Taskmodel != null, u => u.TaskModel == input.Taskmodel)
                                     .Where(input.Tasktype != null, u => u.TaskType == input.Tasktype)
                                     .Where(input.Taskstatus != null, u => u.TaskStatus == input.Taskstatus)
                                     .Where(!string.IsNullOrEmpty(input.ContainerCode), u => EF.Functions.Like(u.ContainerCode, $"%{input.ContainerCode.Trim()}%"))
                                     .Where(!string.IsNullOrEmpty(input.Sourceplace), u => EF.Functions.Like(u.SourcePlace, $"%{input.Sourceplace.Trim()}%"))
                                     .Where(!string.IsNullOrEmpty(input.Toplace), u => EF.Functions.Like(u.ToPlace, $"%{input.Toplace.Trim()}%"))
                                     .Where(input.Aisle != null, u => u.Aisle == input.Aisle)
                                     .Where(!string.IsNullOrEmpty(input.AreaName), u => u.AreaName == input.AreaName)
                                     .OrderBy(PageInputOrder.OrderBuilder<WmsTaskSearch>(input))
                                     .ProjectToType<WmsTaskOutput>()
                                     .ToADPagedListAsync(input.PageNo, input.PageSize);
            return wmsTasks;
        }

        /// <summary>
        /// 查看详情
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("detail")]
        public async Task<List<WmsMaterialContainer>> ManualWare([FromQuery] WmsTaskDetailSearch input)
        {
            return await _wmsMaterialContainerRep.Where(n => n.OrderNo == input.Orderno).ToListAsync();
        }


        /// <summary>
        /// 强制完成
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("FinishWare")]
        [UnitOfWork]
        public async Task FinishWare([FromQuery] UpdateFinishTaskDto input)
        {
            var taskModel = await _wmsTaskRep.FirstOrDefaultAsync(p => p.Id == input.Id);
            if (taskModel.TaskStatus == Core.Enum.TaskStatus.WANCHENG) throw Oops.Oh("任务已完成!");
            if (taskModel.TaskType == Core.Enum.TaskType.RUKU)  //入库
            {
                //检查容器
                var containerModel = await _wmsContainerRep.FirstOrDefaultAsync(n => n.ContainerCode == taskModel.ContainerCode);
                if (taskModel.OrderNo != "N/A" && containerModel.ContainerStatus != Core.Enum.ContainerStatus.ZUPANG) throw Oops.Oh("托盘未进行组盘!");
                if (taskModel.OrderNo == "N/A" && containerModel.ContainerStatus != Core.Enum.ContainerStatus.KOUXIAN) throw Oops.Oh("托盘信息不存在!");

                //检查库位
                var placeModel = await _wmsPlaceRep.DetachedEntities.Where(p => p.PlaceCode == taskModel.ToPlace).ProjectToType<WmsPlace>().FirstOrDefaultAsync();
                if (placeModel == null) throw Oops.Oh("库位不存在!");
                if (placeModel.PlaceStatus != Core.Enum.PlaceStatus.DAIRU) throw Oops.Oh("库位异常货!");

                //物料托盘关系表
                var wmsMaterialContainerList = await _wmsMaterialContainerRep.DetachedEntities
                    .Where(p => p.OrderNo == taskModel.OrderNo).ProjectToType<WmsMaterialContainer>().ToListAsync();

                //创建托盘库位关系表
                var wmsContainerPlaceModel = new WmsContainerPlace()
                {
                    PlaceId = placeModel.Id,
                    PlaceCode = placeModel.PlaceCode,
                    ContainerId = containerModel.Id,
                    ContainerCode = containerModel.ContainerCode,
                    ContainerPlaceStatus = CommonStatus.ENABLE
                };
                await _wmsContainerPlaceRep.InsertAsync(wmsContainerPlaceModel);

                //托盘状态
                containerModel.ContainerStatus = Core.Enum.ContainerStatus.KUWEI;
                await _wmsContainerRep.UpdateAsync(containerModel);

                //更新库位
                placeModel.PlaceStatus = Core.Enum.PlaceStatus.CUNHUO;
                if (taskModel.OrderNo == "N/A") placeModel.EmptyContainer = YesOrNot.Y;
                else placeModel.EmptyContainer = YesOrNot.N;
                await _wmsPlaceRep.UpdateAsync(placeModel);

                //更新任务
                taskModel.TaskStatus = Core.Enum.TaskStatus.WANCHENG;
                await _wmsTaskRep.UpdateAsync(taskModel);

                //更新库存
                foreach (var item in wmsMaterialContainerList)
                {
                    var StockModel = await _wmsMaterialStockRep
                        .Where(p => p.ContainerCode == taskModel.ContainerCode
                        && p.MaterialName == item.MaterialName && p.MaterialNo == item.MaterialNo && p.MaterialBatch == item.MaterialBatch).FirstOrDefaultAsync();
                    if (StockModel != null)
                    {
                        StockModel.PlaceCode = taskModel.ToPlace;
                        StockModel.AreaId = placeModel.WmsArea.Id;
                        StockModel.StockNumber = item.BindQuantity;
                        await _wmsMaterialStockRep.UpdateAsync(StockModel);
                    }
                    else
                    {
                        StockModel = new WmsMaterialStock()
                        {
                            MaterialNo = item.WmsMaterial.MaterialNo,
                            MaterialType = item.WmsMaterial.MaterialType,
                            MaterialName = item.WmsMaterial.MaterialName,
                            MaterialSpec = item.WmsMaterial.MaterialSpec,
                            MaterialBatch = item.WmsMaterial.MaterialBatch,
                            InspectionMethod = item.WmsMaterial.InspectionMethod,
                            UnitType = item.WmsMaterial.UnitType,
                            UnitNo = item.WmsMaterial.UnitNo,
                            StockNumber = item.BindQuantity,
                            PlaceCode = taskModel.ToPlace,
                            ContainerCode = taskModel.ContainerCode,
                            AreaId = placeModel.WmsArea.Id,
                        };
                        await _wmsMaterialStockRep.InsertAsync(StockModel);
                    }
                }
                //空托
                if (taskModel.OrderNo == "N/A")
                {
                    var StockModel = new WmsMaterialStock()
                    {
                        MaterialNo = "N/A",
                        MaterialType = Core.Enum.MaterialType.KONGTUO,
                        MaterialName = "N/A",
                        MaterialSpec = "N/A",
                        MaterialBatch = "N/A",
                        InspectionMethod = Core.Enum.MaterialInspection.MIANJIAN,
                        UnitType = Core.Enum.UnitType.ZHONGLIANG,
                        UnitNo = Core.Enum.UnitnoType.T,
                        StockNumber = 1,
                        PlaceCode = placeModel.PlaceCode,
                        ContainerCode = containerModel.ContainerCode,
                        AreaId = placeModel.AreaId,
                    };
                    await _wmsMaterialStockRep.InsertAsync(StockModel);
                }

            }
            else    //出库操作
            {
                //库位信息
                var placeModel = await _wmsPlaceRep.FirstOrDefaultAsync(p => p.PlaceCode == taskModel.SourcePlace);
                if (placeModel == null) throw Oops.Oh("库位不存在!");
                if (placeModel.PlaceStatus != Core.Enum.PlaceStatus.DAICHU) throw Oops.Oh("库位异常货!");

                //容器信息
                var containerModel = await _wmsContainerRep.FirstOrDefaultAsync(n => n.ContainerCode == taskModel.ContainerCode && n.ContainerStatus == Core.Enum.ContainerStatus.KUWEI);
                if (containerModel == null) throw Oops.Oh("托盘信息不存在!");

                //库位容器关系
                var containerPlaceModel = await _wmsContainerPlaceRep.FirstOrDefaultAsync(p => p.ContainerCode == containerModel.ContainerCode
                   && p.ContainerId == containerModel.Id && p.PlaceCode == placeModel.PlaceCode && p.PlaceId == placeModel.Id && p.ContainerPlaceStatus == CommonStatus.ENABLE);
                if (containerPlaceModel == null) throw Oops.Oh("库位容器关系不存在!");

                //关系对应出库的物料

                var materialContainersList = await _wmsMaterialContainerRep.Where(p => p.ContainerCode == taskModel.ContainerCode
                && p.BindStatus == CommonStatus.ENABLE && p.OrderNo == taskModel.OrderNo).ToListAsync();

                var materialContainersListold = await _wmsMaterialContainerRep.Where(p => p.ContainerCode == taskModel.ContainerCode
                && p.BindStatus == CommonStatus.DISABLE).ToListAsync();

                //库存
                var materialStockList = await _wmsMaterialStockRep.Where(n => n.ContainerCode == taskModel.ContainerCode
                && n.PlaceCode == taskModel.SourcePlace).ToListAsync();

                //库位
                placeModel.PlaceStatus = Core.Enum.PlaceStatus.KONGXIAN;
                placeModel.EmptyContainer = YesOrNot.N;
                await _wmsPlaceRep.UpdateAsync(placeModel);

                //构建出库物料和托盘关系

                var orderNo = "N/A";
                if (materialContainersList.Count > 0) orderNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString();

                foreach (var item in materialContainersListold)
                {
                    //修改
                    item.BindStatus = CommonStatus.DELETED;
                    await _wmsMaterialContainerRep.UpdateAsync(item);
                }
                foreach (var item in materialContainersList)
                {
                    //修改
                    item.BindStatus = CommonStatus.DISABLE;
                    await _wmsMaterialContainerRep.UpdateAsync(item);
                    //新增
                    var bindentranceModel = new WmsMaterialContainer()
                    {
                        ContainerId = item.ContainerId,
                        ContainerCode = item.ContainerCode,
                        MaterialName = item.MaterialName,
                        MaterialNo = item.MaterialNo,
                        MaterialBatch = item.MaterialBatch,
                        MaterialSpec = item.MaterialSpec,
                        MaterialId = item.MaterialId,
                        BindQuantity = item.BindQuantity,
                        BindStatus = CommonStatus.ENABLE,
                        OrderNo = orderNo,
                    };
                    await _wmsMaterialContainerRep.InsertNowAsync(bindentranceModel);
                }

                //修改库存
                foreach (var item in materialStockList)
                {
                    item.PlaceCode = "N/A";
                    item.AreaId = 0;
                    item.StockNumber = 0;
                    await _wmsMaterialStockRep.UpdateAsync(item);
                }
                //禁用托盘库位关系
                containerPlaceModel.ContainerPlaceStatus = CommonStatus.DELETED;
                await _wmsContainerPlaceRep.UpdateAsync(containerPlaceModel);

                //更新任务
                taskModel.TaskStatus = Core.Enum.TaskStatus.WANCHENG;
                await _wmsTaskRep.UpdateAsync(taskModel);

                //托盘状态
                if (taskModel.OrderNo == "N/A") containerModel.ContainerStatus = Core.Enum.ContainerStatus.KOUXIAN;
                else containerModel.ContainerStatus = Core.Enum.ContainerStatus.ZUPANG;
                await _wmsContainerRep.UpdateAsync(containerModel);
            }
        }

        /// <summary>
        /// 更改优先级别
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("UpdateTasklevel")]
        [UnifyResult(typeof(object))]
        public async Task<object> UpdateTasklevel([FromQuery] UpdateTasklevelDto input)
        {
            var taskModel = await _wmsTaskRep.FirstOrDefaultAsync(p => p.Id == input.Id);
            if (taskModel.TaskStatus != Core.Enum.TaskStatus.WEIZHIXING) throw Oops.Oh("只有未执行的任务能进行更改优先级别!");
            taskModel.TaskLevel = input.Tasklevel;
            await _wmsTaskRep.UpdateAsync(taskModel);
            return XnRestfulResultProvider.RESTfulResult();
        }


        /// <summary>
        /// 删除任务
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("DeleteTask")]
        [UnitOfWork]
        public async Task DeleteTask([FromQuery] DeleteTaskDto input)
        {
            var taskModel = await _wmsTaskRep.FirstOrDefaultAsync(p => p.Id == input.Id);
            if (taskModel.TaskStatus != Core.Enum.TaskStatus.WEIZHIXING) throw Oops.Oh("只有未执行的任务才能进行删除!");

            //库位信息
            if (taskModel.TaskType == Core.Enum.TaskType.RUKU)
            {
                var placeModel = await _wmsPlaceRep.FirstOrDefaultAsync(p => p.PlaceCode == taskModel.ToPlace);
                if (placeModel == null) throw Oops.Oh("库位不存在!");
                if (placeModel.PlaceStatus != Core.Enum.PlaceStatus.DAIRU) throw Oops.Oh("库位异常货!");
                placeModel.PlaceStatus = Core.Enum.PlaceStatus.KONGXIAN;
                await _wmsPlaceRep.UpdateAsync(placeModel);
            }
            else
            {
                var placeModel = await _wmsPlaceRep.FirstOrDefaultAsync(p => p.PlaceCode == taskModel.SourcePlace);
                if (placeModel == null) throw Oops.Oh("库位不存在!");
                if (placeModel.PlaceStatus != Core.Enum.PlaceStatus.DAICHU) throw Oops.Oh("库位异常货!");
                placeModel.PlaceStatus = Core.Enum.PlaceStatus.CUNHUO;
                await _wmsPlaceRep.UpdateAsync(placeModel);

                var materialContainerOld = await _wmsMaterialContainerRep.Where(p => p.ContainerCode == taskModel.ContainerCode && p.BindStatus == CommonStatus.DISABLE).ToListAsync();
                foreach (var item in materialContainerOld)
                {
                    item.BindStatus = CommonStatus.ENABLE;
                    await _wmsMaterialContainerRep.UpdateAsync(item);
                }
                var materialContainer = await _wmsMaterialContainerRep.Where(p => p.OrderNo == taskModel.OrderNo).ToListAsync();
                foreach (var item in materialContainer)
                {
                    await _wmsMaterialContainerRep.DeleteNowAsync(item);
                }
            }
            await _wmsTaskRep.DeleteNowAsync(taskModel);
        }
    }
}
